package lumis.service.wsrp.producer;

import java.util.Map;

import javax.portlet.PortletMode;
import javax.portlet.WindowState;

import lumis.portal.PortalContext;
import lumis.portal.servicecontainer.ServiceContainerUrl;
import lumis.portal.serviceinterface.IServiceInterfaceUrl;
import lumis.util.PortalUtil;

import com.sun.portal.container.ChannelMode;
import com.sun.portal.container.ChannelState;
import com.sun.portal.container.ChannelURL;
import com.sun.portal.container.ChannelURLFactory;
import com.sun.portal.container.ChannelURLType;

/**
 * {@link ServiceContainerUrl} implementation used by WSRP Producer.
 *
 * @version $Revision: 11180 $ $Date: 2009-12-04 18:13:02 -0200 (Fri, 04 Dec 2009) $
 * @since 5.5.0
 */
@SuppressWarnings("deprecation")
class ProducerServiceInterfaceURL extends ServiceContainerUrl
{
	/**
	 * Prefix included in all producer generated URL. This is necessary for not
	 * re-encoding producer generated URLs in {@link ProducerContainer} post
	 * processing. It is removed during such post processing.
	 * @since 5.5.0
	 */
	static final String PRODUCER_GENERATED_URL_PREFIX = "_lumProducerURL-" + PortalUtil.generateNewGuid() + "_";
	
	private final ChannelURLFactory channelURLFactory;
	
	/**
	 * The identifier of the service interface instance that is generating the
	 * URL.
	 * @since 5.5.0
	 */
	private final String currentServiceInterfaceInstanceId;

	/**
	 * Creates a URL object used for generating URLs in a WSRP request context.
	 * @param urlType the URL type.
	 * @param channelURLFactory the channel URL factory to be used. 
	 * @param currentServiceInterfaceInstanceId the identifier of the service 
	 * interface instance that is generating the URL.
	 * @since 5.5.0
	 */
	public ProducerServiceInterfaceURL(int urlType, ChannelURLFactory channelURLFactory,
			String currentServiceInterfaceInstanceId)
	{
		super(urlType);
		this.channelURLFactory = channelURLFactory;
		this.currentServiceInterfaceInstanceId = currentServiceInterfaceInstanceId;
	}
	
	/**
	 * Converts an {@link IServiceInterfaceUrl} URL type constant to a 
	 * {@link ChannelURLType} object.
	 * @param urlType the URL type.
	 * @return the corresponding ChannelURLType.
	 * @since 5.5.0
	 */
	private ChannelURLType getChannelURLType(int urlType)
	{
		switch(urlType)
		{
			case RENDER_URL:
				return ChannelURLType.RENDER;
			case ACTION_URL:
				return ChannelURLType.ACTION;
			case EXTERNAL_URL:
				throw new IllegalArgumentException("Cannot convert EXTERNAL_URL to ChannelURLType");
			default:
				throw new IllegalArgumentException("Invalid url type: " + urlType);
		}
	}

	@Override
	public String toString(boolean process)
	{
		final String url;
		
		if (EXTERNAL_URL == getUrlType())
		{
			// external URL needs no special treatment, so just call super
			url = super.toString(process);
		}
		else
		{
			// if the target is the same interface instance, use WSRP compatible URL
			if (getTargetScope() == TARGET_SCOPE_SERVICEINTERFACEINSTANCE && currentServiceInterfaceInstanceId.equals(getTargetId()))
			{
				// create ChannelURL
				ChannelURL channelURL = channelURLFactory.createChannelURL();
				channelURL.setURLType(getChannelURLType(getUrlType()));
				
				// set parameters
				Map<String, String[]> parameters = getParameterMap();
				replaceNullValueWithEmptyString(parameters);
				channelURL.setParameters(parameters);
				
				// set mode and state
				PortletMode portletMode = getPortletMode();
				if (portletMode != null)
					channelURL.setChannelMode(new ChannelMode(portletMode.toString()));
				WindowState windowState = getWindowState();
				if (windowState != null)
					channelURL.setWindowState(new ChannelState(windowState.toString()));
				
				// generate the URL and return it
				url = channelURL.toString();
			}
			else
			{
				// generate an absolute URL
				url = PortalContext.getFrameworkUrl() + "/" + super.toString(process);
			}
		}
		
		// include the producer URL prefix
		return PRODUCER_GENERATED_URL_PREFIX + url;
	}
	
	/**
	 * Replaces any <code>null</code> element inside the string arrays of
	 * the map's values into an empty string.
	 * <p>
	 * {@link ChannelURL} implementation does not work correctly with <code>null</code>
	 * String value, appending them into the URL as if they were the 
	 * string &quot;null&quot;. So this replacement is used as a workaround.
	 * 
	 * @param parameters the parameters map.
	 * @since 5.5.0
	 */
	private void replaceNullValueWithEmptyString(Map<String, String[]> parameters)
	{
		for (String[] values: parameters.values())
		{
			for (int i=0; i<values.length; i++)
				if (values[i] == null)
					values[i] = "";
		}
	}
}
